# !/usr/bin/env python
# encoding: utf-8


"""
  @author: gaogao
  @file: Heater P-V.py
  @time: 2022/3/30 15:51
  @desc:
"""
import time

from math import *
from ATS.hardwarescan import conf_file_manager
from utils.save_setting_2_ini import save_ini_info
from ATS.application.LCR_App.U2722A_App import U2722A_App
from ATS.application.LCR_App.B2901BL_App import B2901BLApp
from ATS.application.LASER_App.L8164B_App import L8164B_App
from ATS.application.LASER_App.N7744C_App import N7744C_App
from ATS.datamanager import data_transfer_station as DataTransferStation
from utils.read_ini_2_dict import get_option_value, get_refrence_data, get_loss_data
from utils.get_wave_power_util import get_wave_power_value, get_wave_loss_gc
from ATS.application.VNA_App.N5225B_App import N5225BApp
from ATS.util.calcu_step_util import get_points_list
from ATS.util.save_data_2_csv_util import saveData2CSV
from utils.find3db_util import find3db_util
from collections import namedtuple
from matplotlib import pyplot as plt
import numpy as np
from ATS.switchdriver.LightSwitchDriver import LightSwitchDriver
from utils.log_util import loggings
from gui import constant

global half_slope_voltage


# 通道1设置扫描电压，通道2、3固定电压
def pv_test(para):
    try:
        result_data = namedtuple("result_data", "subdie,test_item,curve_type,test_result")
        try:
            inst_light = LightSwitchDriver.instance()
            if inst_light.is_connected:
                inst_light.set_all_switch("01", "05")
                time.sleep(1)
                print(inst_light.query_switch())
            else:
                inst_light.connect()
            l8164 = para.l8164_setting
            n7744 = para.n7744_setting
            l8164b_app = L8164B_App(l8164["title"])
            n7744c_app = N7744C_App(n7744["title"])

            l8164b_app.set_power_unit()
            l8164b_app.set_power_value(float(l8164["power_value"]))
            l8164b_app.set_wave_length(int(l8164["wave_length"][0]))
            time.sleep(4)
            p_in = l8164b_app.fetch_input_power()
            l8164b_app.output_on()
            n7744c_app.reset()
            n7744c_app.set_power_wave_length()
            n7744c_app.set_power_unit()
            n7744c_app.set_power_range_auto()
            n7744c_app.set_power_atim(n7744["atim"])

            time.sleep(5)

            smu_setting = para.smu_setting
            smu_dict = {}
            # smu voltage_list channel nplc current_range current_limit //mode sweep
            #
            mes_plans_dict = {"var_func": None, "var1": None, "measure_func": None}
            init_set_list = []
            for smu in smu_setting:
                if smu["smu"] not in smu_dict:
                    smu_dict[smu["smu"]] = U2722A_App(smu["smu"])
                current_inst = smu_dict[smu["smu"]]
                current_voltage_list = smu["voltage_list"]
                current_channel = smu["channel"]
                current_channel_nplc = smu["nplc"]
                current_channel_range = smu["current_range"]
                current_channel_limit = smu["current_limit"]
                init_set_list += [lambda x=current_channel, inst_obj=current_inst: inst_obj.set_voltage_range(x),
                                  lambda x=current_channel_nplc, y=current_channel,
                                         inst_obj=current_inst: inst_obj.set_current_nplc(x, y),
                                  lambda x=current_channel_range, y=current_channel_limit,
                                         z=current_channel, inst_obj=current_inst: inst_obj.set_current_range_limit(x,
                                                                                                                    y,
                                                                                                                    z)]
                if smu["mode"] == "sweep":
                    mes_plans_dict["var1"] = current_voltage_list
                    mes_plans_dict["var_func"] = lambda volt, x=current_channel, inst_obj=current_inst: \
                        inst_obj.set_voltage(volt, x)
                else:
                    init_set_list += [lambda x=current_voltage_list[0], y=current_channel,
                                             inst_obj=current_inst: inst_obj.set_voltage(x, y)]

                if smu["is_measure"]:
                    mes_plans_dict["measure_func"] = lambda x=current_channel, inst_obj=current_inst: abs(
                        float(inst_obj.get_current_value(x)))
            # set init
            for inst_set_func in init_set_list:
                inst_set_func()  # 设置SMU

            # read mes
            # current_list = []  # result list
            power_list = []
            mes_func = mes_plans_dict["measure_func"]
            if mes_func:  # mes func不为空
                if mes_plans_dict["var1"]:  # sweep
                    for volt in mes_plans_dict["var1"]:
                        mes_plans_dict["var_func"](volt)
                        power_value = n7744c_app.get_power_value()
                        power_list.append(float(power_value))
            sweep_list = [float(i) for i in mes_plans_dict["var1"]]
            wave_power_tuple = get_refrence_data()
            loss_gc = get_wave_loss_gc(l8164["wave_length"][0], get_loss_data())
            loss_sys = get_wave_power_value(l8164["wave_length"][0], wave_power_tuple)
            print("p_in", p_in)
            print("loss_sys", loss_sys)
            print("loss_gc", loss_gc)
            for num_index in range(len(power_list)):
                power_list[num_index] = round(
                    (float(p_in) - power_list[num_index] - float(loss_sys) - 2 * float(loss_gc)), 3)
            DataTransferStation.get_DTS().postarraydata("test", result_data(para.subdie, para.test_item, 'line',
                                                                            (sweep_list, power_list)))
            # 寻找P-V曲线上的3db的电压值和IL值
            datas = find3db(sweep_list, power_list)
            if datas and len(datas) == 4:
                # 设置bias电压
                half_slope_voltage = datas[0]
                if mes_plans_dict["var1"]:
                    mes_plans_dict["var_func"](half_slope_voltage)
                    current_value = mes_func()
                # sweep_inst.set_voltage(datas[0], sweep_channel)
                # current_value = sweep_inst.get_current_value(sweep_channel)
                # 计算heater电阻
                heater_resistance = float(half_slope_voltage) / float(current_value)
                save_ini_info(constant.REMEMBER_VALUE, "remember_value", "half_slope_voltage", str(half_slope_voltage))
                save_ini_info(constant.REMEMBER_VALUE, "remember_value", "il", str(datas[3]))
                save_ini_info(constant.REMEMBER_VALUE, "remember_value", "heater_resistance", str(heater_resistance))
                print("heater_resistance", heater_resistance)
                print("半坡电压", datas[0])
                print("il", datas[3])
            else:
                half_slope_voltage = None


        except Exception as e:
            print("eee", e)
            loggings.error("pv_test" + str(e))
    except Exception as e:
        print("error", e)
        loggings.error("pv_test1" + str(e))


def lca_test(n5225bapp):
    return n5225bapp.search_bw()


def plot_curve2(curve_list, title, x, y, max_x, max_y):
    color = ["r", "m", "c", "y"]
    label = ["0s", "60s", "300s", "10s"]
    plt.figure(figsize=(20, 20), dpi=100)
    fig, ax = plt.subplots()
    ax.set_title(f"{title} P-V curve")
    for i in range(len(curve_list)):
        ax.plot(curve_list[i][0], curve_list[i][1], color[i], label=f"{label[i]}")
        ax.plot([max_x], [max_y], "s")
        ax.text(max_x, max_y, f"{str(max_x)},{str(max_y)}")
        ax.plot([x], [y], "s")
        ax.text(x, y, f"{str(x)},{str(y)}")
        ax.set_xlabel("Voltage")
        ax.set_ylabel("Power")
        ax.grid(True)
        ax.legend()
    plt.savefig(f"{title}.png")
    plt.show()


def plot_curve(curve_list):
    plt.figure(figsize=(20, 20), dpi=100)
    fig, ax = plt.subplots()
    ax.plot(curve_list[0], curve_list[1], "y")
    ax.grid(True)
    plt.show()


def cal_slope(x, y):
    slope, intercept = np.polyfit(x, y, 1)
    return slope


def find3db(x_data, y_data):
    max_peak = ""
    peak_index = ""
    min_peak = min(y_data)
    peak_index = y_data.index(min_peak)
    length = len(y_data)
    compare_value = float(min_peak) + 3
    min_x = x_data[peak_index]
    target_x_value, target_y_value = "", ""
    index1 = 0
    for i in range(length):
        result = y_data[i] - compare_value
        if 0 < abs(result) < 0.4:
            if (cal_slope([x_data[i], x_data[i + 1]], [y_data[i], y_data[i + 1]])) < 0:
                target_x_value, target_y_value = x_data[i], y_data[i]
                break
            else:
                continue

    if all([target_x_value, target_y_value, min_x, min_peak]):
        return target_x_value, target_y_value, min_x, min_peak


x_data, y_data = pv_test(locals()['para'])

# loss_gc = get_wave_loss_gc(1271, get_loss_data())
# print(loss_gc)
# n5225bapp = N5225BApp("VNA")
# n5225bapp.start_trigger()
# time.sleep(30)
# print(lca_test(n5225bapp))
# print(n5225bapp.get_snp_data())

# title = "demo"
# curve_list = []
# for i in [0]:
#     x_data, y_data = pv_test(locals()['para'])
#     curve_list.append([x_data, y_data])
#     plot_curve(curve_list)
#     datas = find3db(curve_list[0][0], curve_list[0][1])
#     if datas and len(datas) == 4:
#         print(datas)
#         plot_curve2(curve_list, title, datas[0], datas[1], datas[2], datas[3])
#         saveData2CSV(f"{title}.csv", ["Voltage(V)", "Power(dbm)"], curve_list)
#     else:
#         print("it is error")
